// ========== 头文件 ==========
#include <iostream>
#include <fstream>
#include <sstream>

#include <vector>
#include <set>
#include <unordered_map>

#include <memory>
#include <functional>

using namespace std;

// ========== 宏函数 ==========
#define ERROR_CHECK(cond, msg, cleanup) \
    do{ \
        if(cond) { \
            std::cerr << "Error:" << msg << "(" << __FILE__ << ":" << __LINE__ << ")" << std::endl; \
            cleanup; \
            return; \
        } \
    }while(0)

// ========== 前向声明 ==========
class TextQuery;    // 将文本文件的内容保存在vector<string>中，返回QueryResult对象
class QueryResult;  // 表示查询结果，通常与print联合使用
class Query_base;   // eval相当于TextQuery的query函数，参数是TextQuery，返回QueryResult；rep函数用于返回查询的string表示形式
class Query;        // 用于获得shared_ptr，并且重载运算符
class WordQuery;
class NotQuery;

// ========== 具体实现1 ==========
class TextQuery{
private:
    shared_ptr<vector<string>> _text_vec_ptr;   // 共享指针内容
    
//    vector<string> _text_vec;  // 保存文本内容，单词行号
//    unordered_map<string, set<int>> _text_umap;

public:
    TextQuery(const string &filename);

    //    QueryResult query(string);  // 需要绑定右值, 加const string&
    QueryResult query(const string&) const;
};

#if 0
// 放弃值拷贝，全部改为指针传递地址
class QueryResult{
friend class TextQuery;
private:
//    int test;
//    shared_ptr<vector<string>> _queryresult;    // 此处可能会做与值运算，不建议单例与unique_ptr
//    shared_ptr<vector<string>> _text_vec_ptr;   // 共享指针内容
//    
    vector<string> _text_vec;  // 保存文本内容，单词行号
    unordered_map<string, set<int>> _text_umap;

public:
    QueryResult();
    QueryResult(vector<string> text_vec, unordered_map<string, set<int>> text_umap);    
    void printresult(void);
};
#endif
class QueryResult{
friend class TextQuery;
private:
    shared_ptr<vector<string>> _text_vec_ptr;   // 共享指针内容
    shared_ptr<set<int>> _text_set_ptr;    // 此处可能会做与值运算，不建议单例与unique_ptr
    string _query_word;     // 唯一的作用：打印的时候显示

    //unordered_map<string, set<int>> _text_umap;

public:
    //QueryResult();  // 去掉默认函数，避免无参数查询
    QueryResult(shared_ptr<vector<string>>, shared_ptr<set<int>>, string);      // 需要string，否则print搞不清楚参数    
    //void printresult(const string&) const;
    void printresult() const;
};

class Query_base{
//private:
//public: 
//    // 接口直接公有就可以了，不然调用会很麻烦
//    using EvalFunc = function<QueryResult(const TextQuery&)>;
//    using RepFunc = function<string()>;

//    EvalFunc _eval;
//    RepFunc _rep;
public:
//    QueryResult eval(TextQuery);
//    string rep(string word1, string word2 = "");

//    // 纯虚函数接口
    virtual QueryResult eval(const TextQuery&) const = 0;
    virtual string rep() const = 0;     // 不接受参数，由子类自行维护状态
//
    virtual ~Query_base() = default;    // 基类必须有虚析构函数

//    Query_base(EvalFunc eval, RepFunc rep);

    QueryResult eval(const TextQuery& tq) const; 
    string rep() const;
};

// 暂时考虑仅写Base, 用bind写，一步跳过调用指针
// 发现跳不过去，运算符的重载还指望Query实现
class Query{
private:
    shared_ptr<Query_base> _query_base_ptr;     // 不能直接实例化抽象类，只能通过指针或引用使用
    
public:
    explicit Query(shared_ptr<Query_base>);
    shared_ptr<Query_base> get_query() const;   // 获取指针

    friend Query operator~(const Query&);
    friend Query operator&(const Query&, const Query&);
    friend Query operator|(const Query&, const Query&);
};

class WordQuery {
public:
    WordQuery(const string& word);
};

class NotQuery {
public:
    NotQuery(const string& word);
private:
    QueryResult invert_query(const QueryResult& original);
    
    shared_ptr<Query_base> _query;
};

// ========== 具体实现2 ==========
TextQuery::TextQuery(const string &filename)
    :_text_vec_ptr(make_shared<vector<string>>()){
    ifstream ifs(filename);
    ERROR_CHECK(!ifs.good(), "ifs is not good", ifs.close());
    
    string line;
    //size_t line_index = 0;
    while(getline(ifs, line)){
        _text_vec_ptr->push_back(line);
        
        //istringstream iss(line);
        //string word;
        
        //++line_index;
        //while(iss >> word){
            // _text_vec_ptr->push_back(word);
            // _text_umap.insert(word, line_index);     // 语法错误 
            // _text_umap[word].insert(line_index);
        //}
    }

    ifs.close();
}

#if 0
// 放弃数据成员，而是使用临时容器重写，减少容器相互污染
QueryResult TextQuery::query(const string& word){
    string line;
    size_t line_index = 0;
    for(auto &line : *_text_vec_ptr){
        istringstream iss(line);
        string text;

        ++line_index;
        //  while((iss >> text) && text == word){   // 此处逻辑会遗漏行内匹配
        while(iss >> text){
            if(text == word){
                _text_vec.emplace_back(line);
                _text_umap[word].insert(line_index);
                break;
            }
        }
    }

    QueryResult QR(_text_vec, _text_umap);
    return QR;
//    return {_text_vec, _text_umap, _text_vec_ptr};
//    return *this;
}
#endif

#if 0
QueryResult TextQuery::query(const string& word) const{
    vector<string> _text_vec;
    unordered_map<string, set<int>> _text_umap;

    string line;
    size_t line_index = 0;
    for(auto &line : *_text_vec_ptr){
        istringstream iss(line);
        string text;

        ++line_index;
        //  while((iss >> text) && text == word){   // 此处逻辑会遗漏行内匹配
        while(iss >> text){
            if(text == word){
                _text_vec.emplace_back(line);
                _text_umap[word].insert(line_index);
                break;
            }
        }
    }
    
    return {_text_vec, _text_umap};
}
#endif
QueryResult TextQuery::query(const string& word) const{
    auto _set = make_shared<set<int>>();
    auto _vec = make_shared<vector<string>>();

    string line;
    size_t line_index = 0;
    for(auto &line : *_text_vec_ptr){
        istringstream iss(line);
        string text;

        ++line_index;
        //  while((iss >> text) && text == word){   // 此处逻辑会遗漏行内匹配
        while(iss >> text){
            if(text == word){
                _vec->emplace_back(line);
                _set->insert(line_index);
                break;
            }
        }
    }
    
    return {_vec, _set, word};
}

#if 0
// 直接在构造函数中修改求值
QueryResult::QueryResult(vector<string> text_vec, unordered_map<string, set<int>> text_umap)
    :_text_vec(text_vec)
    ,_text_umap(text_umap){}
#endif

QueryResult::QueryResult(shared_ptr<vector<string>> text_vec_ptr, shared_ptr<set<int>> text_set_ptr, string query_word)
    :_text_vec_ptr(text_vec_ptr)
    ,_text_set_ptr(text_set_ptr)
    ,_query_word(query_word){}

void QueryResult::printresult() const{
    cout << "查询单词: " << _query_word << endl;
    cout << "出现次数: " << _text_vec_ptr->size() << endl;
    cout << "出现行号: ";
    for(auto& set_elem : *_text_set_ptr){
        cout << set_elem << " ";
    }
    cout << "\n";


    for(auto& vec_elem : *_text_vec_ptr){
        cout << vec_elem << "\n";
    }
    cout << "\n";
}

Query_base::Query_base(EvalFunc eval, RepFunc rep)
        :_eval(move(eval)), _rep(move(rep)){}

QueryResult Query_base::eval(const TextQuery& tq) const {
    return _eval(tq); 
}

string Query_base::rep() const {
    return _rep(); 
}

Query::Query(shared_ptr<Query_base> query_base_ptr)
    :_query_base_ptr(query_base_ptr){}

shared_ptr<Query_base> Query::get_query() const{
    return _query_base_ptr;
}

Query operator~(const Query& operand){
    //return make_shared<NotQuery>(operand._query_base_ptr);
    //return Query(make_shared<NotQuery>(operand.get_query()));
    
    //1: 创建NotQuery对象
    //2：包装为Query对象
    //3：调用eval时，通过虚表找到NotQuery::eval
    return Query(make_shared<NotQuery>(operand._query_base_ptr));
}

Query operator&(const Query&, const Query&);
Query operator|(const Query&, const Query&);

WordQuery::WordQuery(const string& word)
    : Query_base(   // 基类初始化
    [word](const TextQuery& tq){ return tq.query(word); },  // lambdai, 已经返回了完整的QueryResult对象，包括vector与map
    [word]{return word;}){  // lambda
}
// 以上初始化等价于
// auto eval_func = [word](auto& tq){ return tq.query(word); }
// auto rep_func = [word]{ return word; }
// Query_base(eval, rep_func);


NotQuery::NotQuery(const string& word)
    : Query_base(
    [word](const TextQuery& tq){ 
        auto result = tq.query(word);
        return invert_query(result);
    },
    [word]{
        return "~(" + ")";
    }){

    }

NotQuery::QueryResult invert_query(const QueryResult& original);
// ========== 测试函数  ==========
void test(){
    TextQuery tq("17_china_daily.txt");

    //tq.query("and");
    QueryResult qr = tq.query("and");
    //qr.printresult();
}

void test2(){
    TextQuery tq("17_china_daily.txt");
    WordQuery wq("and");
    wq.eval(tq).printresult();
}

int main()
{   
    test2();
    return 0;
}

